﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
using InstantMessenger.Properties;
using InstantMessenger.Transports;

namespace InstantMessenger
{
    public partial class MessageHubForm : Form
    {
        private readonly ContextMenu actionsButtonContextMenu;
        private List<Contact> contacts;
        private IEnumerable<ITransport> transports = Enumerable.Empty<ITransport>();
        private DesktopTransport desktopTransport;
        private bool started;
        private ITransport twitterTransport;

        public MessageHubForm()
        {
            InitializeComponent();

            RefreshContacts();

            actionsButtonContextMenu = new ContextMenu();
            actionsButtonContextMenu.Popup += actionsButtonContextMenu_Popup;
            actionsButton.SplitMenu = actionsButtonContextMenu;
            actionsButton.ShowSplit = true;
        }

        void actionsButtonContextMenu_Popup(object sender, EventArgs e)
        {
            actionsButtonContextMenu.MenuItems.Clear();

            if (!started)
            {
                if (peopleListBox.SelectedItem == null)
                {
                    var menuItem = new MenuItem("Add...");
                    menuItem.Click += ShowAddDialog;
                    actionsButtonContextMenu.MenuItems.Add(menuItem);
                }
                else
                {
                    var menuItem = new MenuItem("Edit...");
                    menuItem.Click += ShowEditDialog;
                    actionsButtonContextMenu.MenuItems.Add(menuItem);

                    menuItem = new MenuItem("Remove");
                    menuItem.Click += removeButton_Click;
                    actionsButtonContextMenu.MenuItems.Add(menuItem);
                }
            }
            else
            {
                if (peopleListBox.SelectedItem != null)
                {
                    var contact = (Contact) peopleListBox.SelectedItem;

                    var menuItem = new MenuItem("Go online via Desktop");
                    menuItem.Click += (o, args) => contact.ReplaceTransport(desktopTransport);
                    actionsButtonContextMenu.MenuItems.Add(menuItem);

                    menuItem = new MenuItem("Go online via Twitter");
                    menuItem.Click += (o, args) => contact.ReplaceTransport(twitterTransport);
                    actionsButtonContextMenu.MenuItems.Add(menuItem);

                    if (contact.IsOnline)
                    {
                        menuItem = new MenuItem("Go offline");
                        menuItem.Click += (o, args) => contact.ReplaceTransport(new OfflineTransport());
                        actionsButtonContextMenu.MenuItems.Add(menuItem);
                    }
                }
            }
        }

        void ShowAddDialog(object sender, EventArgs e)
        {
            var dialog = new AddEditContactForm();
            dialog.ShowDialog(this);
            RefreshContacts();
        }

        void ShowEditDialog(object sender, EventArgs e)
        {
            var dialog = new AddEditContactForm(((Contact) peopleListBox.SelectedItem));
            dialog.ShowDialog(this);
            RefreshContacts();
        }

        private static IEnumerable<string> LoadContactsFromSettings()
        {
            if (Settings.Default.ContactNames == null || Settings.Default.ContactNames.Count == 0)
            {
                Settings.Default.ContactNames = new StringCollection();
                Settings.Default.Save();
            }

            return from contactName in Settings.Default.ContactNames.Cast<string>()
                   select contactName;
        }

        private void PopulatePeopleListBox()
        {
            var selectedItem = peopleListBox.SelectedItem;
            peopleListBox.Items.Clear();
            foreach (var contact in contacts)
            {
                peopleListBox.Items.Add(contact);

                contact.PropertyChanged += contact_PropertyChanged;
            }
            peopleListBox.SelectedItem = selectedItem;
        }

        private void contact_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            InvokeOnUiThread(PopulatePeopleListBox);
        }

        private void InvokeOnUiThread(Action action)
        {
            if (InvokeRequired)
                Invoke(new MethodInvoker(action));
            else
                action();
        }

        private void peopleListBox_DoubleClick(object sender, EventArgs e)
        {
            if (!started)
                return;

            var selectedContact = (Contact) peopleListBox.SelectedItem;
            if (!selectedContact.IsOnline)
                selectedContact.ReplaceTransport(desktopTransport);
        }

        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);

            foreach (var transport in transports)
                transport.Stop();
        }

        private static IEnumerable<Contact> GetFriends(Contact contact, IEnumerable<Contact> allContacts)
        {
            // Let's say that everyone is friends with everyone else
            return allContacts.Except(new[] { contact });
        }

        private IEnumerable<ITransport> CreateTransports()
        {
            desktopTransport = new DesktopTransport();
            twitterTransport = new TwitterTransport(Settings.Default.TwitterSettings);

            yield return desktopTransport;
            yield return twitterTransport;
            yield return new ImMeTransport();
        }

        private void removeButton_Click(object sender, EventArgs e)
        {
            var selectedContact = (Contact) peopleListBox.SelectedItem;
            Settings.Default.ContactNames.Remove(selectedContact.Name);
            Settings.Default.Save();

            RefreshContacts();
        }

        private void RefreshContacts()
        {
            // Create a contact for everyone
            contacts = (from name in LoadContactsFromSettings()
                        select new Contact(name)).ToList();
            PopulatePeopleListBox();
        }

        private void startButton_Click(object sender, EventArgs e)
        {
            startButton.Enabled = false;

            started = true;

            foreach (var contact in contacts)
                contact.AddFriends(GetFriends(contact, contacts));

            transports = CreateTransports().ToList();
            foreach (var transport in transports)
                transport.Start(contacts);

            PopulatePeopleListBox();
        }
    }
}
